#include "GribVolume.h"

namespace OCPP
{
	namespace Volume
	{
		GribVolume::GribVolume()
		{

		}

		GribVolume::~GribVolume()
		{

		}

		VolumeWrapper GribVolume::getVolumeVar(String varName, float offset, float scale,bool clip)
		{
			VolumeWrapper volumeWrapper;

	/*		if (clip)
			{
				volumeWrapper.setClip(CRectangle(115.5f, 25.0f, 125.5, 34.0f));
			}

			std::shared_ptr<GribVariable> varable1 = gribWrapper.findVariable(varName);

			if (varable1.get())
			{
				String time = varable1->getTime(0);
				InventoryVector iv1 = varable1->getByTime(time);
				if (iv1.empty())
				{
					return volumeWrapper;
				}
				String levelUnit = iv1[0]->levelUnit;
				String unitName = iv1[0]->unitName;
				StringUtil::toLowerCase(unitName);

				bool convertUnit = unitName == "k";

				StringUtil::toLowerCase(levelUnit);
				double minLevel = 1000000.0;
				double maxLevel = -100000.0;

				for (int i = 0; i < (int)iv1.size(); i++)
				{
					InventoryEx* inv1 = iv1[i].get();

					double levelValue = inv1->level;

					if (minLevel > levelValue) minLevel = levelValue;
					if (maxLevel < levelValue) maxLevel = levelValue;

					VarData varData1 = gribWrapper._NcSyncFile->getData(inv1);

					volumeWrapper.pushT(varData1, offset, scale, convertUnit);
				}
			}*/

			return volumeWrapper;
		}

		VolumeWrapper GribVolume::getVolumeVarUV()
		{
			VolumeWrapper volumeWrapper;
			volumeWrapper.setClip(CRectangle(115.5f, 25.0f, 125.5, 34.0f));

			/*std::shared_ptr<GribVariable> varable1 = gribWrapper.findVariable("u-component_of_wind_Isobaric_surface");
			std::shared_ptr<GribVariable> varable2 = gribWrapper.findVariable("v-component_of_wind_Isobaric_surface");
			if (varable1.get() && varable2.get())
			{
				String time = varable1->getTime(0);
				InventoryVector iv1 = varable1->getByTime(time);
				InventoryVector iv2 = varable2->getByTime(time);
				if (iv1.empty() || iv2.empty())
				{
					return volumeWrapper;
				}
				String levelUnit = iv1[0]->levelUnit;
				StringUtil::toLowerCase(levelUnit);
				double minLevel = 1000000.0;
				double maxLevel = -100000.0;

				for (int i = 0; i < (int)iv1.size(); i++)
				{
					InventoryEx* inv1 = iv1[i].get();
					InventoryEx* inv2 = iv2[i].get();

					double levelValue = inv1->level;

					if (minLevel > levelValue) minLevel = levelValue;
					if (maxLevel < levelValue) maxLevel = levelValue;

					VarData varData1 = gribWrapper._NcSyncFile->getData(inv1);
					VarData varData2 = gribWrapper._NcSyncFile->getData(inv2);

					volumeWrapper.pushUV(varData1, varData2);
				}
			}*/

			return volumeWrapper;
		}

		void GribVolume::extract(String fileName, String outputPath)
		{
			if (!gribWrapper.open(fileName))
			{
				return;
			}

			String name, ext, path;
			StringUtil::splitFullFilename(fileName, name, ext, path);
			outputPath = StringUtil::replaceAll(outputPath,"\\","/");
			if (!StringUtil::endsWith(outputPath, "/"))
			{
				outputPath += "/";
			}

			VolumeWrapper volumeWrapper1 = getVolumeVar("Total_cloud_cover_Isobaric_surface",0.0f,2.0f);
			if (setup(volumeWrapper1))
			{
				writeToW3DM(outputPath + name + "_tcc.w3dm");
			}
			VolumeWrapper volumeWrapper2 = getVolumeVar("Relative_humidity_Isobaric_surface", 0.0f, 2.0f);
			if (setup(volumeWrapper2))
			{
				writeToW3DM(outputPath + name + "_rh.w3dm");
			}
			VolumeWrapper volumeWrapper3 = getVolumeVar("Vertical_velocity_(pressure)_Isobaric_surface", -10.0f, 10.0f);
			if (setup(volumeWrapper3))
			{
				writeToW3DM(outputPath + name + "_vvp.w3dm");
			}
			VolumeWrapper volumeWrapper4 = getVolumeVar("Temperature_Isobaric_surface", -20.0f, 4.0f);
			if (setup(volumeWrapper4))
			{
				writeToW3DM(outputPath + name + "_tem.w3dm");
			}
			VolumeWrapper volumeWrapper5 = getVolumeVarUV();
			if (setup(volumeWrapper5))
			{
				writeToW3DM(outputPath + name + "_speed.w3dm");
			}

			VolumeWrapper volumeWrapper6 = getVolumeVar("Cloud_cover_Isobaric_surface", 0.0f, 2.0f, false);
			if (setup(volumeWrapper6))
			{
				writeToW3DM(outputPath + name + "_tcc.w3dm");
			}
		}

		bool GribVolume::setup(VolumeWrapper& volumeWrapper)
		{
			if (volumeWrapper.dimZ > 0)
			{
#if _DEBUG
				std::cout << "min(" << volumeWrapper.minValue << "),max(" << volumeWrapper.maxValue << ")\n";
#endif
				std::shared_ptr<Image> image = _CreateVolumeImage(
					volumeWrapper.dimX, volumeWrapper.dimY, volumeWrapper.dimZ, PF_BYTE_RGB);

				size_t offset = 0;
				for (int z = 0; z < volumeWrapper.dimZ; z++)
				{
					for (int y = 0; y < volumeWrapper.dimY; y++)
					{
						for (int x = 0; x < volumeWrapper.dimX; x++, offset++)
						{
							uint8* data = image->getData(x, y, z);
							data[0] = volumeWrapper.cdata[offset];
							if (x > 0 && y > 0 && y < volumeWrapper.dimY - 1 && x < volumeWrapper.dimX - 1)
							{
								float v = volumeWrapper.fdata[offset];
								float px = volumeWrapper.fdata[offset + 1];
								float nx = volumeWrapper.fdata[offset - 1];
								float py = volumeWrapper.fdata[offset + volumeWrapper.dimX];
								float ny = volumeWrapper.fdata[offset - volumeWrapper.dimX];
								Vector2 octVec = VolumeUtil::computeNormal(v, px, nx, py, ny);
								data[1] = octVec.x;
								data[2] = octVec.y;
							}
						}
					}
				}

				CRectangle extent = volumeWrapper.clipExtentFixed;
				float w_meta1 = width_in_meter(extent.getMinimum().y + extent.getHeight() * 0.5, extent.getWidth());
				float h_meta1 = height_in_meter(extent.getHeight());
				float d_meta1 = 1e+5;
				int imageS = volumeWrapper.dimX;
				int imageT = volumeWrapper.dimY;
				int imageR = volumeWrapper.dimZ;

				setUint8Image(image);
				getMeta().setSourceFormat(GL_RGB, GL_UNSIGNED_BYTE);
				getMeta().setExtent(extent);
				getMeta().setSize(w_meta1, h_meta1, d_meta1);
				getMeta().setSource(imageS, imageT, imageR);
				return true;
			}
			return false;
		}

		bool GribVolume::convert(std::string fileName)
		{
			std::ifstream ifs(fileName.c_str(), std::ios::binary);
			return convert(ifs);
		}

		bool GribVolume::convert(std::istream& ifs)
		{
			//gribWrapper.read(ifs);
			//VolumeWrapper volumeWrapper;
			//return setup(volumeWrapper);
			return false;
		}
	}
}